// JWT 工具
use chrono::{Duration, Utc};
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use anyhow::{Result, anyhow};

/// JWT 配置结构体
#[derive(Debug, Clone)]
pub struct JwtConfig {
    pub secret: String,        // 密钥
    pub issuer: String,        // 签发者
    pub audience: String,      // 接收者
    pub expires_in: i64,       // 过期时间(秒)
}

impl Default for JwtConfig {
    fn default() -> Self {
        Self {
            secret: "secret_key".to_string(),
            issuer: "my_app".to_string(),
            audience: "users".to_string(),
            expires_in: 3600, // 默认1小时
        }
    }
}

/// JWT 声明(Claims)结构体
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String,           // 主题(通常是用户ID)
    pub exp: i64,              // 过期时间
    pub iat: i64,             // 签发时间
    pub iss: String,          // 签发者
    pub aud: String,         // 接收者
    // 可以添加其他自定义字段
    pub username: String,    // 示例自定义字段 - 用户名
    pub role: String,       // 示例自定义字段 - 用户角色
}

impl Claims {
    /// 创建新的 Claims
    pub fn new(
        sub: String,
        username: String,
        role: String,
        config: &JwtConfig,
    ) -> Self {
        let now = Utc::now();
        let iat = now.timestamp();
        let exp = (now + Duration::seconds(config.expires_in)).timestamp();

        Self {
            sub,
            exp,
            iat,
            iss: config.issuer.clone(),
            aud: config.audience.clone(),
            username,
            role,
        }
    }
}

/// 生成 JWT token
pub fn generate_token(
    user_id: &str,
    username: &str,
    role: &str,
    config: &JwtConfig,
) -> Result<String> {
    // 创建 claims
    let claims = Claims::new(
        user_id.to_string(),
        username.to_string(),
        role.to_string(),
        config,
    );

    // 设置 token 头部，默认使用 HS256 算法
    let header = Header::new(Algorithm::HS256);

    // 生成 token
    encode(
        &header,
        &claims,
        &EncodingKey::from_secret(config.secret.as_ref()),
    )
        .map_err(|e| anyhow!("生成 token 失败: {}", e))
}

/// 验证 JWT token
pub fn verify_token(token: &str, config: &JwtConfig) -> Result<Claims> {
    // 设置验证参数
    let mut validation = Validation::new(Algorithm::HS256);
    validation.set_issuer(&config.issuer);
    validation.set_audience(&config.audience);

    // 验证并解码 token
    let token_data = decode::<Claims>(
        token,
        &DecodingKey::from_secret(config.secret.as_ref()),
        &validation,
    )
        .map_err(|e| anyhow!("验证 token 失败: {}", e))?;

    Ok(token_data.claims)
}